@file:Suppress("SpellCheckingInspection")

package com.link.play.fit.ai.utils

import android.annotation.SuppressLint
import android.os.Build
import android.os.Environment
import java.io.File
import java.util.Properties

sealed interface OEM {
    companion object {
        private const val Unknown = "unknown"
        private const val PropertyHuawei = "ro.build.version.emui"
        private const val PropertyOppo = "ro.build.version.opporom"
        private const val PropertyVivo = "ro.vivo.os.build.display.id"
        private const val PropertyXiaomi = "ro.miui.ui.version.name" // ro.build.version.incremental

        val current: OEM by lazy {
            try {
                return@lazy when {
                    match("huawei", "honor") -> Huawei(getVersion(PropertyHuawei))
                    match("vivo") -> Vivo(getVersion(PropertyVivo))
                    match("oppo") -> Oppo(getVersion(PropertyOppo))
                    match("xiaomi") -> Xiaomi(getVersion(PropertyXiaomi))
                    match("samsung") -> Samsung
                    else -> {
                        val v = getVersion()
                        if (v.contains("flyme")) Meizu(v)
                        else Android
                    }
                 }
            } catch (e: Exception) {
                LogX.e(e = e)
            }
            Android
        }

        @JvmStatic
        inline val isHuawei get() = current is Huawei
        @JvmStatic
        inline val isOppo get() = current is Oppo
        @JvmStatic
        inline val isVivo get() = current is Vivo
        @JvmStatic
        inline val isXiaomi get() = current is Xiaomi
        @JvmStatic
        inline val isSamsung get() = current == Samsung

        private fun match(vararg oem: String): Boolean {
            val brand = Build.BRAND?.lowercase() ?: ""
            val manufacturer = Build.MANUFACTURER?.lowercase() ?: ""
            return when (oem.size) {
                0 -> false
                1 -> brand.contains(oem[0]) || manufacturer.contains(oem[0])
                else -> oem.any { brand.contains(it) || manufacturer.contains(it) }
            }
        }

        private fun getVersion(key: String? = null): String {
            var v = ""
            if (!key.isNullOrEmpty()) {
                v = getSystemProperty(key)
            }
            if (v.isEmpty()) {
                v = runCatching { Build.DISPLAY?.lowercase() }.getOrNull() ?: ""
                if (v == Unknown) v = ""
            }
            return v
        }

        private fun getSystemProperty(key: String): String {
            var prop = getSystemPropertyByShell(key)?.trim()
            if (!prop.isNullOrEmpty() && prop.lowercase() != Unknown) return prop
            prop = getSystemPropertyByStream(key)?.trim()
            if (!prop.isNullOrEmpty() && prop.lowercase() != Unknown) return prop
            prop = getSystemPropertyByReflect(key)?.trim()
            if (!prop.isNullOrEmpty() && prop.lowercase() != Unknown) return prop
            return ""
        }

        private fun getSystemPropertyByShell(key: String): String? {
            return runCatching {
                Runtime.getRuntime()
                    .exec("getprop $key")
                    .inputStream
                    .reader()
                    .buffered(1024)
                    .use { it.readLine() }
            }.getOrNull()
        }

        private fun getSystemPropertyByStream(key: String): String? {
            return runCatching {
                Properties().let {
                    it.load(File(Environment.getRootDirectory(), "build.prop").inputStream())
                    it.getProperty(key)
                }
            }.getOrNull()
        }

        private fun getSystemPropertyByReflect(key: String): String? {
            return runCatching {
                @SuppressLint("PrivateApi")
                val clz = Class.forName("android.os.SystemProperties")
                val getMethod = clz.getMethod("get", String::class.java, String::class.java)
                getMethod.invoke(clz, key, "") as String?
            }.getOrNull()
        }
    }
}

data class Huawei(val version: String) : OEM {
    val v3 = when (version) {
        "EmotionUI 3", "EmotionUI_3.0", "EmotionUI_3.1" -> true
        else -> false
    }
}
data class Xiaomi(val version: String) : OEM {
    private val major = runCatching { version.substring(1).toInt() }.getOrDefault(0)
    val atLeastV6 get() = major >= 6
    val atLeastV7 get() = major >= 7
}
data class Oppo(val version: String) : OEM
data class Vivo(val version: String) : OEM
data class Meizu(val version: String) : OEM {
    private val major = runCatching {
        version.lowercase().replace("flyme", "")
            .replace("os", "")
            .replace(" ", "")
            .substring(0, 1)
            .toInt()
    }.getOrDefault(0)

    val atLeastV4 get() = major >= 4
    val atLeastV7 get() = major >= 7
}
data object Samsung : OEM
data object Android : OEM